package gauge

import (
	

	
	
	
	
	
	
	
	
)

// Option represents an option that can be used to configure a stat panel.
type Option func(gauge *Gauge) error

type ThresholdStep struct {
	Color string
	Value *float64
}

// OrientationMode controls the layout.
type OrientationMode string

const (
	OrientationAuto       OrientationMode = ""
	OrientationHorizontal OrientationMode = "horizontal"
	OrientationVertical   OrientationMode = "vertical"
)

// ReductionType lets you set the function that your entire query is reduced into a
// single value with.
type ReductionType int

const (
	// Min displays the smallest value of the series.
	Min ReductionType = iota
	// Max displays the largest value of the series.
	Max
	// Avg displays the average of the series.
	Avg

	// First displays the first value of the series.
	First
	// FirstNonNull displays the first non-null value of the series.
	FirstNonNull
	// Last displays the last value of the series.
	Last
	// LastNonNull displays the last non-null value of the series.
	LastNonNull

	// Total displays the sum of values in the series.
	Total
	// Count displays the number of value in the series.
	Count
	// Range displays the difference between the minimum and maximum values.
	Range
)

// ValueMap allows to map a value into explicit text.
type ValueMap struct {
	Value string
	Text  string
}

// RangeMap allows to map a range of values into explicit text.
type RangeMap struct {
	From string
	To   string
	Text string
}

// Gauge represents a stat panel.
type Gauge struct {
	Builder *sdk.Panel
}

// New creates a new gauge panel.
func ( string,  ...Option) (*Gauge, error) {
	 := &Gauge{Builder: sdk.NewGauge()}

	.Builder.IsNew = false

	for ,  := range append(defaults(), ...) {
		if  := ();  != nil {
			return nil, 
		}
	}

	return , nil
}

func defaults() []Option {
	return []Option{
		Span(6),
		ValueType(LastNonNull),
		Orientation(OrientationVertical),
		NoValue("N/A"),
		ColorScheme(scheme.ThresholdsValue(scheme.Last)),
	}
}

// Links adds links to be displayed on this panel.
func ( ...links.Link) Option {
	return func( *Gauge) error {
		.Builder.Links = make([]sdk.Link, 0, len())

		for ,  := range  {
			.Builder.Links = append(.Builder.Links, .Builder)
		}

		return nil
	}
}

// DataSource sets the data source to be used by the panel.
func ( string) Option {
	return func( *Gauge) error {
		.Builder.Datasource = &sdk.DatasourceRef{LegacyName: }

		return nil
	}
}

// WithPrometheusTarget adds a prometheus query to the graph.
func ( string,  ...prometheus.Option) Option {
	 := prometheus.New(, ...)

	return func( *Gauge) error {
		.Builder.AddTarget(&sdk.Target{
			RefID:          .Ref,
			Hide:           .Hidden,
			Expr:           .Expr,
			IntervalFactor: .IntervalFactor,
			Interval:       .Interval,
			Step:           .Step,
			LegendFormat:   .LegendFormat,
			Instant:        .Instant,
			Format:         .Format,
		})

		return nil
	}
}

// WithGraphiteTarget adds a Graphite target to the graph.
func ( string,  ...graphite.Option) Option {
	 := graphite.New(, ...)

	return func( *Gauge) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// WithInfluxDBTarget adds an InfluxDB target to the graph.
func ( string,  ...influxdb.Option) Option {
	 := influxdb.New(, ...)

	return func( *Gauge) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// WithStackdriverTarget adds a stackdriver query to the graph.
func ( *stackdriver.Stackdriver) Option {
	return func( *Gauge) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// Span sets the width of the panel, in grid units. Should be a positive
// number between 1 and 12. Example: 6.
func ( float32) Option {
	return func( *Gauge) error {
		if  < 1 ||  > 12 {
			return fmt.Errorf("span must be between 1 and 12: %w", errors.ErrInvalidArgument)
		}

		.Builder.Span = 

		return nil
	}
}

// Height sets the height of the panel, in pixels. Example: "400px".
func ( string) Option {
	return func( *Gauge) error {
		.Builder.Height = &

		return nil
	}
}

// Description annotates the current visualization with a human-readable description.
func ( string) Option {
	return func( *Gauge) error {
		.Builder.Description = &

		return nil
	}
}

// Transparent makes the background transparent.
func () Option {
	return func( *Gauge) error {
		.Builder.Transparent = true

		return nil
	}
}

// Unit sets the unit of the data displayed on this axis.
func ( string) Option {
	return func( *Gauge) error {
		.Builder.GaugePanel.FieldConfig.Defaults.Unit = 

		return nil
	}
}

// Decimals sets the number of decimals that should be displayed.
func ( int) Option {
	return func( *Gauge) error {
		if  < 0 {
			return fmt.Errorf("decimals must be greater than 0: %w", errors.ErrInvalidArgument)
		}

		.Builder.GaugePanel.FieldConfig.Defaults.Decimals = &

		return nil
	}
}

// ValueType configures how the series will be reduced to a single value.
func ( ReductionType) Option {
	return func( *Gauge) error {
		var  string

		switch  {
		case First:
			 = "first"
		case FirstNonNull:
			 = "firstNotNull"
		case Last:
			 = "last"
		case LastNonNull:
			 = "lastNotNull"

		case Min:
			 = "min"
		case Max:
			 = "max"
		case Avg:
			 = "mean"

		case Count:
			 = "count"
		case Total:
			 = "sum"
		case Range:
			 = "range"

		default:
			return fmt.Errorf("unknown value type: %w", errors.ErrInvalidArgument)
		}
		.Builder.GaugePanel.Options.ReduceOptions.Calcs = []string{}

		return nil
	}
}

// ValueFontSize sets the font size used to display the value.
func ( int) Option {
	return func( *Gauge) error {
		.Builder.GaugePanel.Options.Text.ValueSize = 

		return nil
	}
}

// TitleFontSize sets the font size used to display the title.
func ( int) Option {
	return func( *Gauge) error {
		.Builder.GaugePanel.Options.Text.TitleSize = 

		return nil
	}
}

// AbsoluteThresholds changes the background and value colors dynamically within the
// panel, depending on the value. The threshold is defined by a series of steps
// values which, each having a value and an associated color.
func ( []ThresholdStep) Option {
	return func( *Gauge) error {
		 := make([]sdk.ThresholdStep, 0, len())
		for ,  := range  {
			 = append(, sdk.ThresholdStep{
				Color: .Color,
				Value: .Value,
			})
		}

		.Builder.GaugePanel.FieldConfig.Defaults.Thresholds = sdk.Thresholds{
			Mode:  "absolute",
			Steps: ,
		}

		return nil
	}
}

// RelativeThresholds changes the background and value colors dynamically within the
// panel, depending on the value. The threshold is defined by a series of steps
// values which, each having a value defined as a percentage and an associated color.
func ( []ThresholdStep) Option {
	return func( *Gauge) error {
		 := make([]sdk.ThresholdStep, 0, len())
		for ,  := range  {
			 = append(, sdk.ThresholdStep{
				Color: .Color,
				Value: .Value,
			})
		}

		.Builder.GaugePanel.FieldConfig.Defaults.Thresholds = sdk.Thresholds{
			Mode:  "percentage",
			Steps: ,
		}

		return nil
	}
}

// Repeat configures repeating a panel for a variable
func ( string) Option {
	return func( *Gauge) error {
		.Builder.Repeat = &

		return nil
	}
}

// RepeatDirection configures repeating vertical or horizontal
func ( sdk.RepeatDirection) Option {
	return func( *Gauge) error {
		.Builder.RepeatDirection = &

		return nil
	}
}

// ColorScheme configures the color scheme.
func ( ...scheme.Option) Option {
	return func( *Gauge) error {
		scheme.New(&.Builder.GaugePanel.FieldConfig, ...)

		return nil
	}
}

// NoValue defines what to show when there is no value.
func ( string) Option {
	return func( *Gauge) error {
		.Builder.GaugePanel.FieldConfig.Defaults.NoValue = 

		return nil
	}
}

// Orientation changes the orientation of the layout.
func ( OrientationMode) Option {
	return func( *Gauge) error {
		.Builder.GaugePanel.Options.Orientation = string()

		return nil
	}
}